package org.com.yz.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.com.yz.common.config.ConfigureTest;
import org.com.yz.common.config.IRequestService;
import org.com.yz.dal.dao.model.RequestBaseInfo;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;


/**
 * 类的反射机制
 * 通过java中的反射机制，动态的给对象属性赋值，并且获取对象属性值
 *
 * @author feizi
 * @remark
 * @time 2015-2-5下午4:07:03
 */
public class ClassRefUtil {

    private static final MyLog _log = MyLog.getLog(ClassRefUtil.class);

    public static final String token = "9b389216c3c5vtlwf535510b33b9e6ea8";
    //    public static String url = "http://47.98.157.22:3020/api/deposit.htm";
//    public static final String url = "http://47.99.112.97:3020/api/deposit.htm";
    public static String url = "http://127.0.0.1:3023/api/deposit.htm";
//    public static String url = "http://wzz.visastandards.com/api/deposit.htm";
//

    /*public static void main(String[] args) {
        //构建map集合，存放值
        Map<String, String> fieldValueMap = new HashMap<String, String>();
        fieldValueMap.put("id", "10010");
        fieldValueMap.put("cust_tax_code", "440232323232323");
        fieldValueMap.put("cust_name", "飞子科技");
        fieldValueMap.put("contact", "飞子");
        fieldValueMap.put("tel", "15623232323");
        fieldValueMap.put("addr", "飞子广场");
        fieldValueMap.put("product", "飞机");
        fieldValueMap.put("notes", "飞不起来");
        fieldValueMap.put("create_time", "2015-02-06 12:23:55");

        //类的全路径（带包名）
        String className = "com.wx.pojo.repair.RepairProduct";
        Object obj = null;

        try {
            //根据类的路径（类名）来创建Class对象
            Class<?> c = Class.forName(className);

            //创建类的实例
            obj = c.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        //通过反射赋值
        setFieldValue(obj, fieldValueMap,"0");

        //通过反射取值
        int i = 0;
        Map<String, String> getFieldValueMap = getFieldValueMap(obj,"0");

        *//**
     * 1、这个对所有的对象都是通用的
     *//*
        System.out.println("\n\n=========输出调用get方法后取到的值==========");
        for (Entry<String, String> entry : getFieldValueMap.entrySet()) {
            System.out.println("[字段 "+(++i)+"] ["+entry.getKey()+"]   ---   [" + entry.getValue()+"]");
        }

        *//**
     * 2、通过反射方式动态调用set方法赋值，通过原生get方式取值
     * 也可以通过下面这种方式，直接调用类中定义的get方法进行取值
     * 只是需要先把obj对象通过强制类型转换强转成我们需要操作的对象类型
     *//*
     *//*RepairProduct product = (RepairProduct) obj;
        System.out.println("id:"+product.getId());
        System.out.println("cust_tax_code:"+product.getCust_tax_code());
        System.out.println("cust_name:"+product.getCust_name());
        System.out.println("contact:"+product.getContact());
        System.out.println("tel:"+product.getTel());
        System.out.println("addr:"+product.getAddr());
        System.out.println("product:"+product.getProduct());
        System.out.println("notes:"+product.getNotes());
        System.out.println("create_time:"+product.getCreate_time());
        System.out.println("order:"+product.getOrder());*//*
    }*/

    /**
     * 通过反射调用get方法取值，并且以属性名称，和属性值以键值对的形式放于Map集合中
     *
     * @return
     */
    public static Map<String, String> getFieldValueMap(Object obj, String flag) {
        try {
            //通过getClass方法获得obj类的类类型（即Class类型）
            Class<?> c = obj.getClass();

            //定义一个Map集合，存放get方法获取的值
            Map<String, String> getFieldValueMap = new HashMap<String, String>();

            //获取obj对象中自身定义的所有方法,包括public,private,protected
            //(也可以用c.getMethods()，只不过这个是获取obj中所有共有的方法,包括从父类继承的或从接口实现的所有public方法)
            // Method[] methods = c.getDeclaredMethods();
            Method[] methods = null;
            Field[] fields = null;
            if ("1".equals(flag)) {
                methods = c.getMethods();
                fields = c.getDeclaredFields();
            } else {
                methods = c.getMethods();
                fields = c.getFields();
            }

            if (null != fields && fields.length > 0) {
                //遍历fields数组
                for (Field field : fields) {
                    //获取属性的定义名称
                    String fieldName = field.getName();

                    //获取属性的定义类型
                    String fieldType = field.getType().getSimpleName();

                    //拼接属性的get方法
                    String fieldGetMethodName = defineGetOrSetMethod(fieldName, "get");

                    //判断该属性是否定义了get方法
                    if (!checkGetOrSetMethod(methods, fieldGetMethodName)) {
                        continue;
                    }

                    //获取类中定义的get方法
                    Method fieldGetMethod = c.getMethod(fieldGetMethodName, new Class[]{});

                    //调用get方法获取值
                    Object fieldVal = fieldGetMethod.invoke(obj, new Object[]{});

                    String result = null;

                    if ("Date".equals(fieldType)) {
                        result = date2String((Date) fieldVal);
                    } else if ("Long".equals(fieldType)) {
                        result = String.valueOf(fieldVal);
                        BigDecimal db = new BigDecimal(result);
                        result = db.toPlainString();
                    } else {
                        if (null != fieldVal) {
                            result = String.valueOf(fieldVal);
                        }
                    }
                    getFieldValueMap.put(fieldName, result);
                }
            }

            return getFieldValueMap;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 传递Map集合，通过反射调用set方法给属性动态赋值，
     *
     * @param fieldValueMap
     */
    public static void setFieldValue(Object obj, Map<String, String> fieldValueMap, String flag) {
        try {
            //通过getClass方法获得obj类的类类型（即Class类型）
            Class<?> c = obj.getClass();

            Method[] methods = null;
            Field[] fields = null;
            if ("1".equals(flag)) {
                methods = c.getMethods();
                fields = c.getDeclaredFields();
            } else {
                methods = c.getMethods();
                fields = c.getFields();
            }

            //遍历fields属性数组
            if (null != fields && fields.length > 0) {
                for (Field field : fields) {

                    //获取属性的定义名称
                    String fieldName = field.getName();

                    //拼接属性的set方法(自定义的set方法)
                    String fieldSetMethodName = defineGetOrSetMethod(fieldName, "set");

                    //判断该属性是否定义了set方法
                    if (!checkGetOrSetMethod(methods, fieldSetMethodName)) {
                        continue;
                    }

                    //获取类中定义的set方法
                    Method fieldSetMethod = c.getMethod(fieldSetMethodName, field.getType());

                    //取出map集合中需要操作的属性值
                    String fieldValue = fieldValueMap.get(fieldName);

                    if (!isBlank(fieldValue)) {
                        //获取属性的定义类型
                        String fieldType = field.getType().getSimpleName();

                        //根据参数类型判断，调用不同的set方法
                        if ("String".equals(fieldType)) {
                            fieldSetMethod.invoke(obj, fieldValue);
                        } else if ("Date".equals(fieldType)) {
                            fieldSetMethod.invoke(obj, string2Date(fieldValue));
                        } else if (("Integer".equals(fieldType)) || ("int".equals(fieldType))) {
                            fieldSetMethod.invoke(obj, Integer.parseInt(fieldValue));
                        } else if ("Long".equalsIgnoreCase(fieldType)) {
                            fieldSetMethod.invoke(obj, Long.parseLong(fieldValue));
                        } else if ("Double".equalsIgnoreCase(fieldType)) {
                            fieldSetMethod.invoke(obj, Double.parseDouble(fieldValue));
                        } else if ("Boolean".equalsIgnoreCase(fieldType)) {
                            fieldSetMethod.invoke(obj, Boolean.parseBoolean(fieldValue));
                        } else {
                            //没有合适的类型匹配
                            System.out.println("not suitable type" + fieldType);
                        }

                        /**
                         * 当然也可以通过下列这种方式来判断参数的类型，不过还是觉得上面那种方式判断简洁一些，下面要多写一些代码
                         */

                        /*Class[] paramTypes = fieldSetMethod.getParameterTypes();
                        System.out.println("方法的参数类型-paramTypes："+Arrays.toString(paramTypes));

                        if(paramTypes[0] == String.class){
                            fieldSetMethod.invoke(obj, fieldValue);
                        }else if(paramTypes[0] == Date.class){
                            fieldSetMethod.invoke(obj, string2Date(fieldValue));
                        }else if((paramTypes[0] == Integer.class) || (paramTypes[0] == int.class)){
                            fieldSetMethod.invoke(obj, Integer.parseInt(fieldValue));
                        }else if((paramTypes[0] == Long.class) || (paramTypes[0] == long.class)){
                            fieldSetMethod.invoke(obj, Long.parseLong(fieldValue));
                        }else if((paramTypes[0] == Double.class) || (paramTypes[0] == double.class)){
                            fieldSetMethod.invoke(obj, Double.parseDouble(fieldValue));
                        }else if((paramTypes[0] == Boolean.class) || (paramTypes[0] == boolean.class)){
                            fieldSetMethod.invoke(obj, Boolean.parseBoolean(fieldValue));
                        }else{
                            //没有合适的类型匹配
                            System.out.println("not suitable type" + fieldType);
                        }*/


                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 拼接属性的  get 方法 或   set 方法
     * 因为我们自身在定义getter方法的时候，都是将属性名的第一个字母转成大写了
     *
     * @return
     */
    public static String defineGetOrSetMethod(String fieldName, String methodType) {
        if (isBlank(fieldName)) {
            return null;
        }

        //这里也可以直接用“get 或   set”+属性名称，（属性名称的首字母也可以不用转换成大写，上面判断的时候用equalsIgnoreCase忽略大小写就可以了）
        return methodType + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }

    /**
     * String字符串转Date日期格式
     *
     * @param dateStr
     * @return
     */
    public static Date string2Date(String dateStr) {
        if (isBlank(dateStr)) {
            return null;
        }

        try {
            String fmtStr = null;
            if (dateStr.indexOf(":") > 0) {
                fmtStr = "yyyy-MM-dd HH:mm:ss";
            } else {
                fmtStr = "yyyy-MM-dd";
            }

            DateFormat df = new SimpleDateFormat(fmtStr);

            return df.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 日期转字符串
     *
     * @param date
     * @return
     */
    public static String date2String(Date date) {
        if (null == date) {
            return null;
        }

        try {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return df.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断某个属性是否定义了gettter和setter方法
     *
     * @param methods
     * @param fieldMethodName
     * @return
     */
    public static boolean checkGetOrSetMethod(Method[] methods, String fieldMethodName) {
        boolean flag = false;

        if (null != methods && methods.length > 0) {
            for (Method method : methods) {
                if (fieldMethodName.equals(method.getName())) {
                    flag = true;
                }
            }
        }
        return flag;
    }

    /**
     * 判空
     *
     * @param str
     * @return
     */
    public static boolean isBlank(String str) {
        if (null == str || str.trim().length() == 0) {
            return true;
        }
        return false;
    }

    /**
     * 创建返回数据（封装公共部分）
     *
     * @param req     接收的请求数据（不包含bizContent）
     * @param res     返回的请求数据
     * @param code    返回码
     * @param message 返回信息
     * @return
     */
    public static String createRetData(Object req, Object res, String code, String message) {
        setFieldValue(res, ClassRefUtil.getFieldValueMap(req, "0"), "0");
        Map<String, Object> dataMap = new HashMap<>();
        Map<String, String> codeMap = new HashMap<>();
        codeMap.put("code", code);
        codeMap.put("message", message);
        codeMap.put("timestamp", DateUtil.getCurrentDate());
        setFieldValue(res, codeMap, "0");
        dataMap.put("data", JSON.toJSONString(res, SerializerFeature.DisableCircularReferenceDetect));   //禁用FastJson的“循环引用检测”特性。
        RequestBaseInfo reb = JSONObject.parseObject(JSON.toJSONString(res), RequestBaseInfo.class);
        String token = CacheUtil.me().getMd5Token(reb.getMchNo());
        String sign = PayDigestUtil.md5(JSON.toJSONString(res) + "&" + reb.getTimestamp() + token, "UTF-8");
        System.out.println("成功返回数据时，签名原串为：" + JSON.toJSONString(res) + "&" + reb.getTimestamp() + token);
        dataMap.put("sign", sign);
        String result = JSON.toJSONString(dataMap);
//        result = result.replace("\\","");
        _log.info("存管通接口返回" + XmlFormatter.formatJson(result));
        return result;
    }

    /**
     * 创建返回数据（公共参数校验不通过时）
     *
     * @return
     */
    public static String createErrorRetData(JSONObject object, String sign, String errorCode, String errMessage) {
        Map<String, Object> errorMap = new HashMap<>();
        RequestBaseInfo res = new RequestBaseInfo();
        res.setMchNo(object.getString("mch_no"));//商户号
        res.setOutTransNo(object.getString("out_trant_no"));//请求追踪号
        res.setBizType(object.getString("biz_type"));//交易类型
        res.setCode(errorCode);//返回码
        res.setMessage(errMessage);//返回说明
        res.setSignType(object.getString("sign_type"));//签名加密方式
        res.setTimestamp(DateUtil.getCurrentDate());//应答时间戳
        String token = CacheUtil.me().getMd5Token(res.getMchNo());
        String chehckSign = PayDigestUtil.md5(JSON.toJSONString(res) + "&" + res.getTimestamp() + token, "UTF-8");
        System.out.println("失败返回数据时，签名原串为：" + JSON.toJSONString(res) + "&" + res.getTimestamp() + token);
        errorMap.put("sign", chehckSign);
        errorMap.put("data", JSON.toJSONString(res));
        String result = JSON.toJSONString(errorMap);
//        result = result.replace("\\","");
        _log.info("存管通接口返回错误" + XmlFormatter.formatJson(result));
        return result;
    }


    /**
     * 绑卡
     */
    public static void bindBankCardTest() {
        Map<String, String> bizContentMap = new HashMap<>();
        bizContentMap.put("mch_accnt_no", "T0020181019133749000000");
        bizContentMap.put("card_accnt_type", "1");
        bizContentMap.put("card_no", "622908121000127413");
        bizContentMap.put("bank_name", "中国农业银行");
        bizContentMap.put("bank_branch_name", "杭州滨江支行");
        bizContentMap.put("user_name", "Undead");//业务数据
        bizContentMap.put("card_phone", "13111111111");
        bizContentMap.put("order_no", "T0000010");
        bizContentMap.put("notify_url", "http://comch.visastandards.com:3022/api/withdraw/notify.htm");
        if ("1".equals(bizContentMap.get("card_accnt_type"))) {
            bizContentMap.put("cert_type", "0");
            bizContentMap.put("card_type", "0");
            bizContentMap.put("cert_no", "310101198701010019");
            bizContentMap.put("bank_no", "309391000011");
            bizContentMap.put("card_cvn", "");
            bizContentMap.put("card_expire_date", "");
        }

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("biz_type", "mchsub.bind.bankcard");
        dataMap.put("mch_no", "T888");
        dataMap.put("out_mch_accnt_no", "O0001");
        dataMap.put("sign_type", "MD5");
        dataMap.put("timestamp", DateUtil.getCurrentDate());
        dataMap.put("biz_content", bizContentMap);
        dataMap.put("out_trans_no", "R00001");//公共参数

        String data = JSON.toJSONString(dataMap);
        HashMap<String, String> params = new HashMap<String, String>();
        String sign = PayDigestUtil.md5(data + "&" + dataMap.get("timestamp") + token, "UTF-8");//计算签名
        params.put("data", data);
        params.put("sign", sign);//组装请求参数
        String json = null;
        json = txn(url, params, "");//发送请求
        JSONObject po = JSONObject.parseObject(json);//jsonString 转 jsonObject

        String resultData = po.getString("data");//返回data

        if (!"0000".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n请求失败:" + JSONObject.parseObject(resultData).getString("code") + "---" + JSONObject.parseObject(resultData).getString("message"));
        } else {
            System.out.println("\n请求成功");
        }
        if ("102".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n签名验证失败");
            System.out.println("\n请求数据签名原串为：" + data + "&" + dataMap.get("timestamp") + token);
            System.out.println("\n请求签名为：" + sign);
        }
        String resultSign = po.getString("sign");//返回签名
        String resultTime = JSONObject.parseObject(resultData).getString("timestamp");//返回数据时间戳
        String checkSign = PayDigestUtil.md5(resultData + "&" + resultTime + token, "UTF-8");//调用方验签

        if (!resultSign.equals(checkSign)) {
            System.out.println("\n返回数据验签失败！");
        }
        System.out.println("\n返回数据调用方计算后的签名原串为：" + resultData + "&" + resultTime + token);
        System.out.println("\n返回签名为：" + resultSign);

        System.out.println("\n 返回报文为：" + XmlFormatter.formatJson(po.toJSONString()));
    }

    /**
     * 创建子商户测试
     */
    public static String createMchSubTest() {
        Map<String, String> bizContentMap = new HashMap<>();
        bizContentMap.put("mch_accnt_name", "商户测试"+ToolUtil.getRandomString(3));
        bizContentMap.put("out_mch_accnt_no", "T00"+ToolUtil.getRandomString(3));
        bizContentMap.put("link_name", "2");
        bizContentMap.put("link_phone", "2");
        bizContentMap.put("link_email", "");//业务数据

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("biz_type", "mchsub.create");
        dataMap.put("mch_no", "T888");
        dataMap.put("sign_type", "MD5");
        dataMap.put("timestamp", DateUtil.getCurrentDate());
        dataMap.put("biz_content", bizContentMap);
        dataMap.put("out_trans_no", "R00001");//公共参数

        String data = JSON.toJSONString(dataMap);
        HashMap<String, String> params = new HashMap<String, String>();
        String sign = PayDigestUtil.md5(data + "&" + dataMap.get("timestamp") + token, "UTF-8");//计算签名
        params.put("data", data);
        params.put("sign", sign);//组装请求参数
        String json = null;
        json = txn(url, params, "");//发送请求
        JSONObject po = JSONObject.parseObject(json);//jsonString 转 jsonObject

        String resultData = po.getString("data");//返回data

        if (!"0000".equals(JSONObject.parseObject(resultData).getString("code"))) {
//            System.out.println("\n请求失败:" + JSONObject.parseObject(resultData).getString("code") + "---" + JSONObject.parseObject(resultData).getString("message"));
        } else {
//            System.out.println("\n请求失败");
        }
        if ("102".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n签名验证失败");
            System.out.println("\n请求数据签名原串为：" + data + "&" + dataMap.get("timestamp") + token);
            System.out.println("\n请求签名为：" + sign);
        }
        String resultSign = po.getString("sign");//返回签名
        String resultTime = JSONObject.parseObject(resultData).getString("timestamp");//返回数据时间戳
        String checkSign = PayDigestUtil.md5(resultData + "&" + resultTime + token, "UTF-8");//调用方验签

        if (!resultSign.equals(checkSign)) {
            System.out.println("\n返回数据验签失败！");
        }
//        System.out.println("\n返回数据调用方计算后的签名原串为：" + resultData + "&" + resultTime + token);
//        System.out.println("\n返回签名为：" + checkSign);
//
//        System.out.println("\n 返回报文为：" + XmlFormatter.formatJson(po.toJSONString()));

        return JSONObject.parseObject(resultData).getString("mch_accnt_no");
    }


    /**
     * 创建子商户测试
     */
    public static String withDrawTest() {
        Map<String, String> bizContentMap = new HashMap<>();
        bizContentMap.put("order_no", "O00"+ToolUtil.getRandomString(3));
        bizContentMap.put("type", "SUPER");
        bizContentMap.put("mch_accnt_no", "T0020181114150712000008");
        bizContentMap.put("card_no", "6217856200010501208");//业务数据
        bizContentMap.put("amount", "1");//业务数据
        bizContentMap.put("notify_url", "www.baiwu.com");//业务数据


        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("biz_type", "mchaccnt.withdraw");
        dataMap.put("mch_no", "T888");
        dataMap.put("sign_type", "MD5");
        dataMap.put("timestamp", DateUtil.getCurrentDate());
        dataMap.put("biz_content", bizContentMap);
        dataMap.put("out_trans_no", "R00001");//公共参数

        String data = JSON.toJSONString(dataMap);
        HashMap<String, String> params = new HashMap<String, String>();
        String sign = PayDigestUtil.md5(data + "&" + dataMap.get("timestamp") + token, "UTF-8");//计算签名
        params.put("data", data);
        params.put("sign", sign);//组装请求参数
        String json = null;
        json = txn(url, params, "");//发送请求
        JSONObject po = JSONObject.parseObject(json);//jsonString 转 jsonObject

        String resultData = po.getString("data");//返回data

        if (!"0000".equals(JSONObject.parseObject(resultData).getString("code"))) {
//            System.out.println("\n请求失败:" + JSONObject.parseObject(resultData).getString("code") + "---" + JSONObject.parseObject(resultData).getString("message"));
        } else {
//            System.out.println("\n请求失败");
        }
        if ("102".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n签名验证失败");
            System.out.println("\n请求数据签名原串为：" + data + "&" + dataMap.get("timestamp") + token);
            System.out.println("\n请求签名为：" + sign);
        }
        String resultSign = po.getString("sign");//返回签名
        String resultTime = JSONObject.parseObject(resultData).getString("timestamp");//返回数据时间戳
        String checkSign = PayDigestUtil.md5(resultData + "&" + resultTime + token, "UTF-8");//调用方验签

        if (!resultSign.equals(checkSign)) {
            System.out.println("\n返回数据验签失败！");
        }
//        System.out.println("\n返回数据调用方计算后的签名原串为：" + resultData + "&" + resultTime + token);
//        System.out.println("\n返回签名为：" + checkSign);
//
//        System.out.println("\n 返回报文为：" + XmlFormatter.formatJson(po.toJSONString()));

        return JSONObject.parseObject(resultData).getString("mch_accnt_no");
    }


    /**
     * 分账接口测试
     */
    public static String dispatchTest() {


        Map<String, String> bizContentMap = new HashMap<>();
        bizContentMap.put("mch_accnt_no", "T0020181031094411000000");
        bizContentMap.put("order_no", "T00"+ToolUtil.getRandomString(18));
        bizContentMap.put("trans_no", ToolUtil.getRandomString(5));
        bizContentMap.put("dispatch_event", "pay");
        bizContentMap.put("dispatch_type", "1");//业务数据
        bizContentMap.put("amount","100");
        bizContentMap.put("trans_time",DateUtil.getDay());
        bizContentMap.put("trans_channel","wx");

        List  list = new ArrayList();
        list.add(bizContentMap);
        Map<String,Object> accntDetaiMap = new HashMap<>();
        accntDetaiMap.put("split_accnt_detail",list);

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("biz_type", "mchaccnt.dispatch");
        dataMap.put("mch_no", "T888");
        dataMap.put("sign_type", "MD5");
        dataMap.put("timestamp", DateUtil.getCurrentDate());
        dataMap.put("biz_content", accntDetaiMap);
        dataMap.put("out_trans_no", "R00001");//公共参数

        String data = JSON.toJSONString(dataMap);
        HashMap<String, String> params = new HashMap<String, String>();
        String sign = PayDigestUtil.md5(data + "&" + dataMap.get("timestamp") + token, "UTF-8");//计算签名
        params.put("data", data);
        params.put("sign", sign);//组装请求参数
        String json = null;
        json = txn("http://wzz.visastandards.com/api/deposit.htm", params, "");//发送请求
        JSONObject po = JSONObject.parseObject(json);//jsonString 转 jsonObject

        String resultData = po.getString("data");//返回data

        if (!"0000".equals(JSONObject.parseObject(resultData).getString("code"))) {
//            System.out.println("\n请求失败:" + JSONObject.parseObject(resultData).getString("code") + "---" + JSONObject.parseObject(resultData).getString("message"));
        } else {
//            System.out.println("\n请求失败");
        }
        if ("102".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n签名验证失败");
            System.out.println("\n请求数据签名原串为：" + data + "&" + dataMap.get("timestamp") + token);
            System.out.println("\n请求签名为：" + sign);
        }
        String resultSign = po.getString("sign");//返回签名
        String resultTime = JSONObject.parseObject(resultData).getString("timestamp");//返回数据时间戳
        String checkSign = PayDigestUtil.md5(resultData + "&" + resultTime + token, "UTF-8");//调用方验签

        if (!resultSign.equals(checkSign)) {
            System.out.println("\n返回数据验签失败！");
        }
//        System.out.println("\n返回数据调用方计算后的签名原串为：" + resultData + "&" + resultTime + token);
//        System.out.println("\n返回签名为：" + checkSign);
//
//        System.out.println("\n 返回报文为：" + XmlFormatter.formatJson(po.toJSONString()));\
        String bizContent = JSONObject.parseObject(resultData).getString("biz_content");

        String accntDetail = JSONObject.parseObject(bizContent).getString("split_accnt_detail");
        String amount = JSONObject.parseArray(accntDetail).get(0).toString();
        return JSONObject.parseObject(amount).getString("amount_after_event");
    }

    /**
     * 定时查询未绑定成功卡测试
     */
    public static void checkBind() {
        String url = "127.0.0.1:3020//api/pay/banktest.htm";
        txn(url, null, "");

    }


    /**
     * 加密测试
     */
    public static void md5() {
        String checkSign = "{\"biz_content\":{\"mch_accnt_name\":\"李帅康商家\",\"link_email\":\"\":\"905676920@qq.com\",\"o\",\"out_mch_accnt_no\":\"12345678910\",\"link_phone\":\"18636850521\",\"link_name\":\"李帅康\"},\"biz_type\":\"\":\"mchsub.create\",\"o\",\"out_trans_no\":\"T0020181015174200000000\",\"mch_no\":\"80000004\",\"sign_type\":\"MD5\",\"timestamp\":\"20181015174200\"}&201810151742009b389216c3c5vtlwf535510b33b9e6ea7";
        String sign = PayDigestUtil.md5(checkSign, "UTF-8");
        System.out.println(sign);
    }

    /**
     * 往账接口测试
     */
    public static String nostro() {
        Map<String, String> bizContentMap = new HashMap<>();
        bizContentMap.put("mch_accnt_no", "T0020180903101306000001");
        bizContentMap.put("card_no", "3301040160007902813");
        bizContentMap.put("amt", "1");//业务数据

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("biz_type", "mchsub.bind.nostro");
        dataMap.put("mch_no", "T888");
        dataMap.put("out_mch_accnt_no", "O0002");
        dataMap.put("sign_type", "MD5");
        dataMap.put("timestamp", DateUtil.getCurrentDate());
        dataMap.put("biz_content", bizContentMap);
        dataMap.put("out_trans_no", "R00001");//公共参数

        String data = JSON.toJSONString(dataMap);
        HashMap<String, String> params = new HashMap<String, String>();
        String sign = PayDigestUtil.md5(data + "&" + dataMap.get("timestamp") + token, "UTF-8");//计算签名
        params.put("data", data);
        params.put("sign", sign);//组装请求参数
        String json = null;
        json = txn(url, params, "");//发送请求
        JSONObject po = JSONObject.parseObject(json);//jsonString 转 jsonObject

        String resultData = po.getString("data");//返回data

        if (!"0000".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n请求失败:" + JSONObject.parseObject(resultData).getString("code") + "---" + JSONObject.parseObject(resultData).getString("message"));
        } else {
//            System.out.println("\n请求成功");
        }
        if ("102".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n签名验证失败");
            System.out.println("\n请求数据签名原串为：" + data + "&" + dataMap.get("timestamp") + token);
            System.out.println("\n请求签名为：" + sign);
        }
        String resultSign = po.getString("sign");//返回签名
        String resultTime = JSONObject.parseObject(resultData).getString("timestamp");//返回数据时间戳
        String checkSign = PayDigestUtil.md5(resultData + "&" + resultTime + token, "UTF-8");//调用方验签

        if (!resultSign.equals(checkSign)) {
            System.out.println("\n返回数据验签失败！");
        }
//        System.out.println("\n返回数据调用方计算后的签名原串为：" + resultData + "&" + resultTime + token);
//        System.out.println("\n返回签名为：" + checkSign);
//
//        System.out.println("\n 返回报文为：" + XmlFormatter.formatJson(po.toJSONString()));
        return JSONObject.parseObject(resultData).getString("message");
    }

    /**
     * 解绑接口测试
     *
     * @return
     */
    public static void bankcardUntie() {
        Map<String, String> bizContentMap = new HashMap<>();
        bizContentMap.put("mch_accnt_no", "T0020181016113428000000");
        bizContentMap.put("card_no", "622908121000127413");

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("biz_type", "mchsub.bind.nostro");
        dataMap.put("mch_no", "80000004");
        dataMap.put("out_mch_accnt_no", "O0002");
        dataMap.put("sign_type", "MD5");
        dataMap.put("timestamp", DateUtil.getCurrentDate());
        dataMap.put("biz_content", bizContentMap);
        dataMap.put("out_trans_no", "R00001");//公共参数

        String data = JSON.toJSONString(dataMap);
        HashMap<String, String> params = new HashMap<String, String>();
        String sign = PayDigestUtil.md5(data + "&" + dataMap.get("timestamp") + token, "UTF-8");//计算签名
        params.put("data", data);
        params.put("sign", sign);//组装请求参数
        String json = null;
        json = txn(url, params, "");//发送请求
        JSONObject po = JSONObject.parseObject(json);//jsonString 转 jsonObject

        String resultData = po.getString("data");//返回data

        if (!"0000".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n请求失败:" + JSONObject.parseObject(resultData).getString("code") + "---" + JSONObject.parseObject(resultData).getString("message"));
        } else {
            System.out.println("\n请求失败");
        }
        if ("102".equals(JSONObject.parseObject(resultData).getString("code"))) {
            System.out.println("\n签名验证失败");
            System.out.println("\n请求数据签名原串为：" + data + "&" + dataMap.get("timestamp") + token);
            System.out.println("\n请求签名为：" + sign);
        }
        String resultSign = po.getString("sign");//返回签名
        String resultTime = JSONObject.parseObject(resultData).getString("timestamp");//返回数据时间戳
        String checkSign = PayDigestUtil.md5(resultData + "&" + resultTime + token, "UTF-8");//调用方验签

        if (!resultSign.equals(checkSign)) {
            System.out.println("\n返回数据验签失败！");
        }
        System.out.println("\n返回数据调用方计算后的签名原串为：" + resultData + "&" + resultTime + token);
        System.out.println("\n返回签名为：" + checkSign);

        System.out.println("\n 返回报文为：" + XmlFormatter.formatJson(po.toJSONString()));
    }

    public static String txn(String url, Map<String, String> params, String mchNo) {

        String json = null;
        try {
            IRequestService requestor = IRequestService.getInstance();
            json = (String) requestor.sendPost(url, params);
        } catch (IOException e) {
            json = ConfigureTest.TXN_ERROR_RESULT;
        } catch (Exception e) {
            json = ConfigureTest.SYS_ERROR_RESULT;
        }
        return json;
    }

    /**
     * 对私鉴权测试
     * @throws IOException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    public static void authenCard() throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchAlgorithmException, KeyManagementException {
        Map<String, String> reqMap = new HashMap<>();
        reqMap.put("product", "21");
        reqMap.put("mid", "181024007");
        reqMap.put("spOrder", "989888881");
        reqMap.put("txnDate", DateUtil.getCurrentDate());
        reqMap.put("cardNo", "6226097807427613");
        reqMap.put("name", "范晶");
        reqMap.put("certNo", "42028119920311121X");
        reqMap.put("phone", "15072042823");
        String str = createLinkStringByGet(reqMap);
        str += "&key=6EE8A8DC7BF08CE5F00EE1649E295385";
        System.out.println("签名原串为：" + str);
        String sign = PayDigestUtil.md5(str, "utf-8");
        System.out.println("签名为：----" + sign);

        Map<String, String> reqMap2 = new HashMap<>();

        reqMap2.put("product", "21");
        reqMap2.put("mid", "181024007");
        reqMap2.put("spOrder", "989888881");
        reqMap2.put("txnDate", DateUtil.getCurrentDate());
        reqMap2.put("cardNo", AESUtil.encrypt("6226097807427613", "6EE8A8DC7BF08CE5F00EE1649E295385"));
        reqMap2.put("name", "范晶");
        reqMap2.put("certNo", AESUtil.encrypt("42028119920311121X", "6EE8A8DC7BF08CE5F00EE1649E295385"));
        reqMap2.put("phone", "15072042823");
        reqMap2.put("sign", sign);
        String url = "https://v.fucongpay.com/api/verify";
        String json = txn(url, reqMap2, "");

        IRequestService requestor = IRequestService.getInstance();
        System.out.println("请求的数据为:" + reqMap2);
//        requestor.sendPost(url,reqMap);
        System.out.println(json);
    }


    /**
     * 多线程并发执行某项任务
     *
     * @param concurrentThreads    并发线程数，可以用来模拟并发访问用户数
     * @param times                总共执行多少次
     * @param task                 任务
     * @param requestHandler       结果处理器
     * @param executeTimeoutMillis 执行任务总超时
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static <T> void concurrentTest(long concurrentThreads, int times, final Callable<T> task,
                                          RequestHandler<T> requestHandler, long executeTimeoutMillis)
            throws InterruptedException, ExecutionException {

        ExecutorService executor = Executors.newFixedThreadPool((int) concurrentThreads);
        List<Future<T>> results = new ArrayList<Future<T>>(times);

        long startTimeMillis = System.currentTimeMillis();
        for (int i = 0; i < times; i++) {
            results.add(executor.submit(task));
        }
        executor.shutdown();

        boolean executeCompleteWithinTimeout = executor.awaitTermination(executeTimeoutMillis, TimeUnit.MILLISECONDS);
        System.out.println(TimeUnit.MILLISECONDS);
        if (!executeCompleteWithinTimeout) {
            System.out.println("Execute tasks out of timeout [" + executeTimeoutMillis + "ms]");

            /*
             * 取消所有任务
             */
            for (Future<T> r : results) {
                r.cancel(true);
            }
        } else {
            long totalCostTimeMillis = System.currentTimeMillis() - startTimeMillis;

            // 线程池此时肯定已关闭，处理任务结果
            for (Future<T> r : results) {
                if (requestHandler != null) {
                    requestHandler.handle(r.get());
                }
            }

            System.out.println("concurrent threads: " + concurrentThreads + ", times: " + times);
            System.out.println("total cost time(ms): " + totalCostTimeMillis + "ms, avg time(ms): " + ((double) totalCostTimeMillis / times));
            System.out.println("tps: " + (double) (times * 1000) / totalCostTimeMillis);
        }
    }


    public static String createLinkStringByGet(Map<String, String> params) throws UnsupportedEncodingException {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
//            value = URLEncoder.encode(value, "UTF-8");
            if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }

    public static void main(String[] args) throws IOException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchAlgorithmException, KeyManagementException, ExecutionException, InterruptedException {

       /* System.out.println(4824279.67 - 550811.88 - 3394732.48 - 10595.95 - 127080.11 - 15930.69 - 194215.66 - 180224.08 - 14389.00-1.03-0.67);
        System.out.println(-25793258 + 339473248);

        System.out.println(339473248 + 98766979);

        System.out.println(1059595+ 12708011);*/

        System.out.println(1593069+ 19421566);

        System.out.println(1438900+ 18022408);

        System.out.println(-362233107 +339473248 );

        System.out.println(+ 13767606 -362233107 +339473248);

        System.out.println(77505903+ 339473248);

        System.out.println(77505903+ 339473248 + 13767606);


        System.out.println(66568894 + 339473248 + 13767606 ); // 6日10点存管前余额

        System.out.println(66568894 + 339473248 + 13767606  + 21014635);//后余额


        System.out.println(-400847000 + 339473248 + 13767606); //6月10日 在途前余额

        System.out.println(-400847000 + 339473248 + 13767606 + 21014635); //6月10日 在途后余额

        System.out.println(4697836.76 - 4361536.94 -1.02 -0.67 -0.01  );



        //        withDrawTest();
       /* System.out.println(DateUtil.date2Str(new Date(), "hhmmss"));

        System.out.println(1778900.14 - 1442602.02);

        System.out.println(223.18+319.33 + 117433.05 + 74700.81 - 195120.83);*/
        // 支付宝手续费+微信手续费+微信结算到账+支付宝结算到账- 记账 = 问题键金额（记账，但是未打款金额）

        // 微信结算到账+支付宝结算到账 - 记账（在途中加手续费） = 问题键金额
        /*concurrentTest(50, 10000 ,
                () -> {
                    try {
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    return dispatchTest();
                },
                result -> System.out.println("result: " + result), 6000000);*/

        /*String star = "<?xml version=\"1.0\" encoding=\"GBK\"?>    <FOX>    <SIGNONMSGSRQV1>        <SONRQ>           <DTCLIENT>2018-11-14 15:25:09</DTCLIENT>           <CID>1100343164</CID>           <USERID>zzp1</USERID>           <USERPASS>a11111</USERPASS>           <GENUSERKEY>N</GENUSERKEY>         </SONRQ></SIGNONMSGSRQV1>  <SECURITIES_MSGSRQV1>   <SCUSTSTMTTRNRQ>     <TRNUID>20181114152509hHTC</TRNUID>   <SCUSTSTMTRQ>      <ACCTFROM>        <ACCTID>117010100100000177</ACCTID>      </ACCTFROM>  </SCUSTSTMTRQ></SCUSTSTMTTRNRQ></SECURITIES_MSGSRQV1></FOX>";
        try {
            System.out.println(XmlFormatter.formatXml(star));
        } catch (Exception e) {
            e.printStackTrace();
        }
        String str = "[{\"sex\":\"男\",\"history\":\"\",\"technician\":\"\",\"name\":\"我问问\",\"occupation\":\"巍巍荡荡\",\"age\":\"30\",\"weight\":\"130\",\"height\":\"175\",\"code\":\"21\",\"shape\":\"多的\",\"other\":\"\",\"year\":\"\"},{\"longShortLegs\":\"左\",\"distance\":\"1\",\"footProblem\":[\"正常腿型\",\"正常足\"],\"internalExternal\":\"中立位\",\"internalExternalCharacters\":\"内八字\"},[{\"wz\":\"位置1\",\"jg\":[\"right\",\"横弓塌陷\"]},{\"wz\":\"位置2\",\"jg\":[\"left\",\"横弓塌陷\"]}],{\"left1\":1,\"left2\":2,\"reght1\":3,\"reght2\":4,\"resultsText\":\"没毛病\"}]";

        JSONArray jsonArray = JSON.parseArray(str);


        System.out.println(jsonArray.get(0));//
        System.out.println(jsonArray.get(1));
        System.out.println(jsonArray.get(2));
        System.out.println(JSON.parseArray(JSON.toJSONString(jsonArray.get(2))).get(0));
        String arrstr = JSON.toJSONString(jsonArray.get(2));
        String obj = JSON.toJSONString(JSON.parseArray(arrstr).get(0));
        String wz = JSONObject.parseObject(obj).getString("wz");
        String jg = JSONObject.parseObject(obj).getString("jg");
        System.out.println(wz);
        System.out.println(JSON.parseArray(jg).get(0));
        System.out.println(jsonArray.get(3));*/
//        authenCard();


        String a = "1.238761976E-10";

        BigDecimal db = new BigDecimal(a);

       /* System.out.println("科学计数：" + db.toString());

        System.out.println("普通计数：" + db.toPlainString());

        System.out.println(DateUtil.formatDate(new Date(), "HH:mm:ss"));

        System.out.println(DateUtil.compareDate("12:00:00", DateUtil.formatDate(new Date(), "HH:mm:ss"), "HH:mm:ss"));

        System.out.println(DateUtil.date2Str(new Date(), "yyyyMMdd"));

        System.out.println(AES.getInstance().encrypt("yeshuo20160712".getBytes("UTF8")));*/
//        md5();
//        CreateMchSubTest();//创建子商户
//
//        BindBankCardTest();//绑定银行卡

//        checkBind();//定时查询未绑定卡

//        nostro();//往账
    }
}